using System;
using System.Threading;

using Jeffrey.XFramework.XCrawl;
using Jeffrey.XFramework.XInteract;

namespace Jeffrey.XFramework
{
    public abstract class Processor
    {
        protected internal Processor(String name, String description, String classname, String path)
            : this(name, description, classname, path, null) { }
        protected internal Processor(String name, String description, String classname, String path, Filter filter)
        {
            m_IsEnabled            = true;
            m_DefaultNextProcessor = null;
            m_Name                 = name;
            m_Description          = description;
            m_ClassName            = classname;
            m_Path                 = path;
            m_Filter               = filter;
        }

        public void Process(CrawlUri curi)
        {
            if (!m_IsEnabled)
                return;

            Boolean accept = true;

            if (m_Filter != null)
                accept = m_Filter.Accepts(curi);

            if (accept)
            {
                if (curi.m_Status == CrawlUri.StatusCode.N_RejectedByAll)
                {
                    /*
                     * this processor is the first processor accepts the uri
                     * changes the status to SUCCEED
                     */
                    curi.m_Status = CrawlUri.StatusCode.S_Succeed;
                }
                else
                {
                    /* the uri has been processed before, do not change its status */
                    if (curi.m_Status != CrawlUri.StatusCode.S_Succeed)
                        return;
                }
                /*
                 * Trigger some event here...not in Spiderun
                 */
                m_Controller.Xbuject.OnSpiderStatusChanged(new SpiderStatusPackage(Int32.Parse(Thread.CurrentThread.Name),
                                                                                   m_Name,
                                                                                   CrawlSpider.SpiderStatus.EntryingProcessor
                                                                                   )
                                                           );
                innerProcess(curi);
                m_Controller.Xbuject.OnSpiderStatusChanged(new SpiderStatusPackage(Int32.Parse(Thread.CurrentThread.Name),
                                                                                   m_Name,
                                                                                   CrawlSpider.SpiderStatus.FinishedProcessor
                                                                                   )
                                                           );
            }
            else
                innerRejectProcess(curi);
        }

        public virtual Boolean Inintialize()
        {
            //by default return true...
            return true;
        }

        protected abstract void innerProcess(CrawlUri curi);
        protected virtual  void innerRejectProcess(CrawlUri curi) 
        { 
            /*by defualt do nothing...log this uri*/
        }

        public Processor NextProcessor
        {
            get { return m_DefaultNextProcessor; }
            set { m_DefaultNextProcessor = value; }
        }
        public Processor PreProcessor
        {
            get { return m_DefaultPreProcessor; }
            set { m_DefaultPreProcessor = value; }
        }
        public Boolean Enabled
        {
            get { return m_IsEnabled; }
            set { m_IsEnabled = value; }
        }
        public String Name
        {
            get { return m_Name; }
        }
        public String Description
        {
            get { return m_Description; }
        }
        public Filter Filter
        {
            get { return m_Filter; }
            set { m_Filter = value; }
        }
        public String Path
        {
            get { return m_Path; }
        }
        public String ClassName
        {
            get { return m_ClassName; }
        }
        public ProcessorChain Chain
        {
            get { return m_Chain; }
        }

        internal void CloneProcessor(Processor p)
        {
            if (p == null)
                throw new NullReferenceException("Processor");

            this.m_Chain      = p.m_Chain;
            this.m_ClassName  = p.m_ClassName;
            this.m_Controller = p.m_Controller;
            this.m_DefaultNextProcessor = p.m_DefaultNextProcessor;
            this.m_Description = p.m_Description;
            this.m_Filter      = p.m_Filter;
            this.m_IsEnabled   = p.m_IsEnabled;
            this.m_Name = p.m_Name;
            this.m_Path = p.m_Path;
        }

        protected internal CrawlController m_Controller;

        private Boolean   m_IsEnabled;
        private Processor m_DefaultNextProcessor;
        private Processor m_DefaultPreProcessor;
        private Filter    m_Filter;

        private String    m_Path;
        private String    m_ClassName;
        private String    m_Name;
        private String    m_Description;

        internal ProcessorChain m_Chain;
    }
}
